#include <iostream>
#include <ceres/ceres.h>

using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;

const int kNumObservations=31;

const double data[]={
    16.4178594446026,15.5055750076103,	9.02895847476385,	8.04869382220386,
17.1110066251625,	15.5055750076103,	9.02895847476385,	8.33567340112161,
17.8041556582038,	15.5055750076103,	9.02895847476385,	9.30466192051836,
17.1110066251625,	15.5055750076103,	8.33581129540278,	7.98789362366333,
17.1110066251625,	15.5055750076103,	9.43442358327164,	8.64404646470674,
17.1110066251625,	15.5055750076103,	9.7221056553238,	9.07784496481907,
17.1110066251625,	13.896140785322,	9.02895847476385,	8.26836834555168,
17.1110066251625,	14.8124296721249,	9.02895847476385,	8.32529942929465,
16.4178608453833,	14.8124285433256,	9.02895847476385,	8.04869382150925,
16.8233259534915,	14.8124285433256,	9.02895847476385,	8.19316700645445,
17.1110080259433,	14.8124285433256,	9.02895847476385,	8.33567340007896,
17.5164731340514,	14.8124285433256,	9.02895847476385,	8.93764799921966,
17.6706238138787,	14.8124285433256,	9.02895847476385,	8.67705276186428,
17.8041552065032,	14.8124285433256,	9.02895847476385,	9.30466192095357,
17.9219382421596,	14.8124285433256,	9.02895847476385,	9.36920044209114,
18.0272987578174,	14.8124285433256,	9.02895847476385,	9.5089623844663,
18.2096203146114,	14.8124285433256,	9.02895847476385,	9.59234399340535,
17.1110080259433,	14.8124285433256,	8.33581129436664,	7.98789362248229,
17.1110080259433,	14.8124285433256,	8.7412764024748,	8.20924452318198,
17.1110080259433,	14.8124285433256,	9.02895847492658,	8.32151888209157,
17.1110080259433,	14.8124285433256,	9.25210202624079,	8.54023353838866,
17.1110080259433,	14.8124285433256,	9.43442358303475,	8.64404646539611,
17.1110080259433,	14.8124285433256,	9.58857426286201,	8.8171187018098,
17.1110080259433,	14.8124285433256,	9.72210565548653,	9.07784496427305,
17.1110080259433,	14.8124285433256,	9.94524920680074,	8.84874526934931,
17.1110080259433,	14.8124285433256,	9.94524920680074,	8.45282607368421,
17.1110080259433,	13.8961378114514,	9.94524920680074,	8.26836834568694,
17.1110080259433,	14.8124285433256,	9.94524920680074,	8.325299428087,
17.1110080259433,	15.2178936514338,	9.94524920680074,	8.3090458753769,
17.1110080259433,	15.5055757238855,	9.94524920680074,	8.37329717560527,
17.1110080259433,	15.9110408319937,	9.94524920680074,	8.31341303789197,
};

struct EXponetialResidual{
    EXponetialResidual(double x1, double x2, double x3, double y):x1_(x1),x2_(x2),x3_(x3),y_(y){}
    template <typename T> 
    bool operator() (const T *const m1,
                     T* residual) const {
        //residual[0]=T(y_)-abcd[0]*x1_-abcd[1]*x2_-abcd[2]*x3_+abcd[3];
        residual[0]=T(y_)-m1[0]*x1_-m1[1]*x2_-m1[2]*x3_+m1[3];
        
                         return true;
    }
private:
   const double x1_, x2_, x3_, y_;
};

int main(int argc, char** argv)
{
    double m1=1,m2=1,m3=1,m4=0;
    double abcd[4]={m1,m2,m3,m4};
    
    Problem problem;
    for(int i=0;i<kNumObservations;++i){
        problem.AddResidualBlock(
            new AutoDiffCostFunction<EXponetialResidual,1,4>(        
            new EXponetialResidual(data[4*i],data[4*i+1],data[4*i+2],data[4*i+3])
        ),
            NULL,
            abcd
        );
    }
    
    Solver::Options options;
    options.max_num_iterations=30;
    options.linear_solver_type=ceres::DENSE_QR;
    options.minimizer_progress_to_stdout=true;
    
    Solver::Summary summary;
     ceres::Solve(options, &problem,&summary);
    std::cout<<summary.BriefReport()<<"\n";
    std::cout<<"inieial m1 "<<1.0<<std::endl;
    std::cout<<"initial m1 "<<abcd[0]<<"\n";
    return 0;
}
